package com.ohuang.wallpapermanager.compose

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.math.sqrt

@Composable
fun rememberFilePainter(filePath: String): BitmapPainter {
    val bitmapState = remember(filePath) {
        mutableStateOf(BitmapPainter(ImageBitmap(1, 1)))
    }
    LaunchedEffect(key1 = filePath, block = {
        withContext(Dispatchers.IO) {
            try {
                val asImageBitmap = BitmapFactory.decodeFile(filePath).asImageBitmap()
                bitmapState.value = BitmapPainter(asImageBitmap)
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
    })

    return bitmapState.value
}

@Composable
fun rememberFilePainterSafe(filePath: String, maxPixSize: Int = 1024 * 1024): BitmapPainter {
    val bitmapState = remember(filePath) {
        mutableStateOf(BitmapPainter(ImageBitmap(1, 1)))
    }

    LaunchedEffect(key1 = filePath, block = {
        withContext(Dispatchers.IO) {
            try {
                val options = BitmapFactory.Options()
                options.inJustDecodeBounds = true
                BitmapFactory.decodeFile(filePath,options)
                val size = options.outWidth * options.outHeight
                var bitmap:Bitmap? = null
                if (size > maxPixSize) {
                    val div = sqrt(size * 1.0f / maxPixSize)
                    val with = (options.outWidth / div).toInt()
                    val height = (options.outHeight / div).toInt()
                    if (with > 0 && height > 0) {
                        // 计算inSampleSize值
                        options.inSampleSize = calculateInSampleSize(options, with, height)
                        options.inJustDecodeBounds = false;
                        bitmap = BitmapFactory.decodeFile(filePath,options)
                    }
                }else{
                    bitmap=BitmapFactory.decodeFile(filePath)
                }
                val asImageBitmap = bitmap!!.asImageBitmap()
                bitmapState.value = BitmapPainter(asImageBitmap)
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
    })
    return bitmapState.value
}

@Composable
fun rememberUriPainter(uri: Uri): Painter {
    val context = getContext()
    val bitmapState = remember(uri) {
        mutableStateOf(BitmapPainter(ImageBitmap(1, 1)))
    }

    LaunchedEffect(key1 = uri, block = {
        withContext(Dispatchers.IO) {
            try {
                context.contentResolver.openInputStream(uri).use {
                    bitmapState.value =
                        BitmapPainter(BitmapFactory.decodeStream(it).asImageBitmap())
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
    })

    return bitmapState.value

}

@Composable
fun rememberUriPainterSafe(uri: Uri, maxPixSize: Int = 1024 * 1024): Painter {
    val context = getContext()
    val bitmapState = remember(uri) {
        mutableStateOf(BitmapPainter(ImageBitmap(1, 1)))
    }

    LaunchedEffect(key1 = uri, block = {
        withContext(Dispatchers.IO) {
            try {
                context.contentResolver.openInputStream(uri).use {

                    var decodeStream = BitmapFactory.decodeStream(it)
                    val size = decodeStream.width * decodeStream.height
                    if (size > maxPixSize) {
                        val div = sqrt(size * 1.0f / maxPixSize)
                        val with = (decodeStream.width / div).toInt()
                        val height = (decodeStream.height / div).toInt()
                        if (with > 0 && height > 0) {
                            val scale = scale(decodeStream, with, height)
                            decodeStream.recycle()
                            decodeStream = scale
                        }
                    }
                    val asImageBitmap = decodeStream.asImageBitmap()
                    bitmapState.value = BitmapPainter(asImageBitmap)
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
    })

    return bitmapState.value

}

/**
 * 缩放图片
 */
private fun scale(
    bitmap: Bitmap,
    toWidth: Int,
    toHeight: Int
): Bitmap {
    val width = bitmap.width
    val height = bitmap.height
    val matrix = Matrix()
    matrix.postScale(toWidth * 1.0f / width, toHeight * 1.0f / height)
    return Bitmap.createBitmap(
        bitmap, 0, 0, bitmap.width, bitmap.height,
        matrix, true
    )
}


private fun calculateInSampleSize(
    options: BitmapFactory.Options,
    reqWidth: Int, reqHeight: Int
): Int {
    // 源图片的高度和宽度
    val height = options.outHeight
    val width = options.outWidth
    var inSampleSize = 1
    if (height > reqHeight || width > reqWidth) {
        // 计算出实际宽高和目标宽高的比率
        val heightRatio = Math.round(height.toFloat() / reqHeight.toFloat())
        val widthRatio = Math.round(width.toFloat() / reqWidth.toFloat())
        // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高
        // 一定都会大于等于目标的宽和高。
        inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
    }
    return inSampleSize
}